from umqtt import MQTTClient
import time
import machine
import  mytimer
import myconfig
import gc
import utime
import ubinascii
import ujson
import wifi_connect 
import myuart
import _thread
import app

b_check_updata = False  #检测更新

client = None
wlan   = None
b_updata = False
isconnect = False

mqtt_count  = 0  #MQTT心跳间隔计数
mqtt_count2 = 0  #MQTT连接超时计数

wifi_obj = None
cat1_static = "reset_mqtt"
count_10s = 0
csq = ""

#上报mqtt信息到服务器
def send_message():

    try:
        value_sum   = myuart.modbus_data[1]<<16 | myuart.modbus_data[0]  #光电数
        value_out   = myuart.modbus_data[3]<<16 | myuart.modbus_data[2]  #剔除数
        value_speed = myuart.modbus_data[5]<<16 | myuart.modbus_data[4]  #速度
        value_temp  = (myuart.modbus_data[7]-1000)/10                    #温度

        if value_sum != 0:
            pre_produce =  value_out/value_sum   #剔除率
        else:
            pre_produce = 0

        pre_produce = pre_produce*100.0
        str_pre_produce = '{:.2f}'.format(pre_produce)    #两位小数
        
        mess_data = {'list_data': [
            {
                'name': '检测数',
                'value': '0',
                'unit': '个'
            },
            {
                'name': '剔除数',
                'value': '0',
                'unit': '个'
            },
            {
                'name': '剔除率',
                'value': '0.0',
                'unit': '%'
            },
            {
                'name': '速度',
                'value': '0.0',
                'unit': ''
            },
            {
                'name': '温度',
                'value': '0.0',
                'unit': '度'
            },
        ]}

        # 赋值
        mess_data['list_data'][0]['value'] = str(value_sum)          #光电数
        mess_data['list_data'][1]['value'] = str(value_out)          #剔除数
        mess_data['list_data'][2]['value'] = str_pre_produce         #剔除率
        mess_data['list_data'][3]['value'] = str(value_speed)        #生产速度
        mess_data['list_data'][4]['value'] = str(value_temp)         #温度

        #封装数据
        final_data = {
            "devic_id":myconfig.devic_id,
            "mess_data":mess_data
        }

        # 发送数据 
        if myconfig.type_net == 0:
            publish(myconfig.devic_id+"/data",ujson.dumps(final_data).encode('utf8'), retain=True, qos=0) #自身主题
            publish("web_server/message_data",ujson.dumps(final_data).encode('utf8'), retain=True, qos=0) #服务器主题
        else:
            CAT_4G_PUB(myconfig.devic_id+"/data",ujson.dumps(final_data)) #自身主题
            CAT_4G_PUB("web_server/message_data",ujson.dumps(final_data)) #服务器主题

    except Exception as e:
        print("send_message error:")
        print(e)
        


# MQTT 调试信息 
# ESP32/info
def mqtt_print(msg):
    if myconfig.type_net == 0:
        client.publish("ESP32/info", msg)
    else:
        CAT_4G_PUB("ESP32/info",msg)

#MQTT 信息回调
def sub_callback(topic, msg):
    global mqtt_count2
    global client
    global b_check_updata

    try:
        #心跳主题
        if topic.decode() == myconfig.devic_id+"/keep_alive":
            mqtt_count2 = 0  #清除mqtt超时计数    

        #自身命令
        if topic.decode() == myconfig.devic_id+"/cmd":
            if msg.decode() == "reset":
                mqtt_print("reset")  
                machine.reset()

            #获取mqtt数据
            if msg.decode() == "get_data":
                mytimer.b_send_mqtt_data = True

            #更新
            if msg.decode() == "updata":            
                mqtt_print(myconfig.devic_id+":updata...")
                b_check_updata = True   


            #获取版本
            if msg.decode() == "version":     
                version_str = myconfig.devic_id +'/version:' + myconfig.version 
                mqtt_print(version_str)    

        #数据主题 mqtt转uart0
        if topic.decode() == myconfig.devic_id+"/data_rx":
            pass

        # 公共命令
        if topic.decode() == "light_cmd":

            if msg.decode() == "updata":
                mqtt_print(myconfig.devic_id+":updata...")
                b_check_updata = True  

            if msg.decode() == "version":     
                version_str = myconfig.devic_id +'/version:' + myconfig.version     
                mqtt_print(version_str)      


    except Exception:
        print("mqtt sub_callback Exception")

#mqtt 信息循环
#检测信息接收  
def mqtt_check_msg():    
    try:        
        client.check_msg()   
    except Exception: 
        print("mqtt 异常断开..")
        print("正在重新连接mqtt..")
        gc.collect()
        start_mqtt()
        
#连接服务器
def connect_mqtt_huaxin():
    
    client_id = myconfig.devic_id + myconfig.client_id      #实例ID = 设备id+预设的实例id 
    client = MQTTClient(client_id=client_id, server=myconfig.mserver,port=myconfig.port,
                        user=myconfig.mqtt_name,password=myconfig.mqtt_passwd,keepalive=600)
    return client

# 连接mqtt服务器
def start_mqtt():
    global client

    try: 
        gc.collect()
        print("start connect mqtt...")   
        myconfig.run_status = "start connect mqtt..."

        client = connect_mqtt_huaxin()
        client.set_callback(sub_callback)    
        client.connect()

        #订阅主题
        print("start subscribe node...")   
        client.subscribe(myconfig.devic_id+"/keep_alive")
        client.subscribe(myconfig.devic_id+"/cmd")
        client.subscribe(myconfig.devic_id+"/data_rx")
        client.subscribe("light_cmd")

        mqtt_print(myconfig.devic_id +": power up and has connected to mqtt server")
        print("connected to mqtt server success")
        myconfig.run_status = "connected to mqtt server success"    

    except Exception as e:
        print("connect mqtt Exception",e)
        myconfig.run_status = "connect mqtt Exception"
        myconfig.error_code = 1
        myconfig.error_str = "connect mqtt Exception"
        time.sleep(5)
        machine.reset()


# 发布消息
def publish(topic, msg, retain=False, qos=0):
    client.publish(topic, msg, retain,qos)

#超时重连检测 100hz 0.01s
def check_keep_alive():
    global mqtt_count,mqtt_count2
    global cat1_static

    #发送心跳信号
    mqtt_count = mqtt_count + 1
    if mqtt_count > 6000: #1mim 
        mqtt_count = 0
        if myconfig.type_net == 0:
            client.publish(myconfig.devic_id+"/keep_alive","A")
        elif myconfig.type_net == 1:
            CAT_4G_PUB(myconfig.devic_id+"/keep_alive",'A')
            
    #mqtt超时重连
    mqtt_count2 = mqtt_count2 + 1
    if mqtt_count2 > 12000: #2mim 
        mqtt_count2 = 0
        if myconfig.type_net == 0:
            start_mqtt()
        elif myconfig.type_net == 1:
            cat1_static = "reset_mqtt"

#MQTT主循环任务
def mqtt_loop():
    global count_10s
    count_10s = count_10s +1
    if count_10s >= 1000:
       count_10s = 0
       if(myconfig.type_net == 1):
           print("AT+CSQ") #获取4g信号值

    #上传MQTT数据
    if mytimer.b_send_mqtt_data:
        mytimer.b_send_mqtt_data = False
        send_message()  

    #循环任务
    mytimer.led_loop()
    mytimer.check_io_status()
    check_keep_alive()
    mytimer.wdt.feed()
    utime.sleep_ms(10)


#通过wifi连接mqtt服务器
def wifi_mqtt():
    global wifi_obj

    mytimer.wdt = machine.WDT(timeout=120000)  #120s
    wifi_obj = wifi_connect.myWifiSet(time_out_sec = 60)
    if wifi_obj.isconnected:   
        #LED PWM
        mytimer.set_led_status(10,80)         
        start_mqtt()
        while True:
            if b_check_updata == False:
                mqtt_check_msg()
                mqtt_loop()

# 通过cat1连接mqtt服务器
def cat1_mqtt():
    global cat1_static

    client_id = myconfig.devic_id + myconfig.client_id      #实例ID = 设备id+预设的实例id

    str_mqtt_user = "AT+MCONFIG=" + client_id +','+myconfig.mqtt_name+','+myconfig.mqtt_passwd #登录信息
    str_mqtt_server = "AT+MIPSTART=" + myconfig.mserver +','+ str(myconfig.port)    #服务器信息
    str_mqtt_connect = "AT+MCONNECT=1,65535"
    mytimer.wdt = machine.WDT(timeout=120000)  #120s

    while True:

        if cat1_static == "power_up":
             print("AT+CGREG?") #查询当前GPRS注册状态
             myconfig.run_status = "查询当前GPRS注册状态"
             utime.sleep(1)
        elif cat1_static == "CGREG_OK":
             print("AT+CGATT?") #查看当前GPRS附着状态
             myconfig.run_status = "查看当前GPRS附着状态"
             utime.sleep(1)
        elif cat1_static == "CGATT_OK":
             print("AT+MQTTMODE=1") #mqtt MQTT信息形式>>hex格式
             myconfig.run_status = "mqtt 发布信息形式>>hex格式"
             print(str_mqtt_user)   #设置MQTT登录账户信息
             utime.sleep(1)
        elif cat1_static == "set_mqtt_acount_OK":
             print(str_mqtt_server) #设置MQTT服务器信息 地址+端口号
             myconfig.run_status = "设置MQTT服务器信息 地址+端口号"
             utime.sleep(1)
        elif cat1_static == "set_mqtt_server_OK":
             print(str_mqtt_connect) #新建连接会话
             myconfig.run_status = "新建连接会话"
             utime.sleep(1)
        elif cat1_static == "mqtt_connect_OK":
             #订阅主题 
             CAT_4G_SUB(myconfig.devic_id+"/keep_alive")
             CAT_4G_SUB(myconfig.devic_id+"/cmd")
             CAT_4G_SUB(myconfig.devic_id+"/data_rx")
             CAT_4G_SUB("light_cmd")       
             myconfig.run_status = "订阅主题 "  
             cat1_static = "mqtt_loop"                         
        elif cat1_static == "mqtt_loop":  #连接成功
             myconfig.run_status = "4G_MQTT连接成功"
             mqtt_loop()
        elif cat1_static == "reset_mqtt":  #复位连接
             print("AT+MDISCONNECT")
             utime.sleep(2)
             print("AT+MIPCLOSE")
             utime.sleep(2)
             cat1_static = "power_up"
             myconfig.run_status = "复位连接"
            

#连接MQTT服务
def connect_mqtt():

    # wifi版
    if(myconfig.type_net == 0):
        print("WIFI MODEL")
        wifi_mqtt()
    #4G版
    else:
        print("4G MODEL")
        cat1_mqtt()

#4G_MQTT发布消息
def CAT_4G_PUB(topic,str,retain='1',qos='0'):
    str = str.encode('utf8').hex()
    str_mqtt_pub = "AT+MPUB=" + topic + ',' + qos + ','+retain+',' + "\"" + str + "\""
    print(str_mqtt_pub)

#订阅主题
def CAT_4G_SUB(topic):
    print("AT+MSUB="+topic+','+'0')
    utime.sleep(1)

#4G_mqtt接收信息回调
def sub_callback_cat1(topic,data):
    topic = topic.strip("\"").encode()            #去除"
    data  = ubinascii.unhexlify(data.strip('\n')) #去除\n  hex字符形式数据转为二进制数据
    sub_callback(topic, data)


#主串口接收回调
def receive_cat1(str):
    global cat1_static,csq

    #4G信号值
    if str.find("+CSQ:") != -1:
        csq = str.strip()

    if cat1_static == "power_up":
        if str.find("+CGREG: 0,1") != -1:
            cat1_static = "CGREG_OK"
    elif cat1_static == "CGREG_OK":
        if str.find("+CGATT: 1") != -1:
            cat1_static = "CGATT_REC"    #中间状态
    elif cat1_static == "CGATT_REC":
        if str.find("OK") != -1:
            cat1_static = "CGATT_OK"
    elif cat1_static == "CGATT_OK":
        if str.find("OK") != -1:
            cat1_static = "set_mqtt_acount_OK"
    elif cat1_static == "set_mqtt_acount_OK":     
        if str.find("CONNECT OK") != -1:        #服务器连接成功
            cat1_static = "set_mqtt_server_OK"
    elif cat1_static == "set_mqtt_server_OK":
        if str.find("CONNACK OK") != -1:        #成功建立MQTT会话
            cat1_static = "mqtt_connect_OK"    
    elif cat1_static == "mqtt_loop":     
        if str.find("+MSUB") != -1:   #消息接收   
            try: 
                msg = str.split(":")[1]
                sub_callback_cat1(msg.split(',')[0].strip(),msg.split(',')[2])      
            except Exception as e:
                print(e) 


    

